import { getRandomStr } from '@utils/base/string'
/**
 * 防抖函数（在一定时间内连续触发，只执行最后一次执行的）
 * @param {Function} func
 * @param {number} wait
 * @param {boolean} immediate
 * @return {*}
 */
export function debounce(func, wait = 100, immediate) {
  let timeout, args, context, timestamp, result

  const later = function () {
    // 据上一次触发时间间隔
    const last = +new Date() - timestamp

    if (timeout) clearTimeout(timeout)
    // 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
    if (last < wait && last > 0) {
      timeout = setTimeout(later, wait - last)
    } else {
      timeout = null
      // 如果设定为immediate===true，因为开始边界已经调用过了此处无需调用
      if (!immediate) {
        result = func.apply(context, args)
        if (!timeout) context = args = null
      }
    }
  }

  return function (...args) {
    context = this
    timestamp = +new Date()
    const callNow = immediate && !timeout
    // 如果延时不存在，重新设定延时
    if (!timeout) timeout = setTimeout(later, wait)
    if (callNow) {
      result = func.apply(context, args)
      context = args = null
    }
    return result
  }
}

/**
 * 节流方法
 * @param {function} callback
 * @param {date} time
 */
export function throttling(callback, time = 5000) {
  // 是否第一次请求
  let isFirst = true
  // 执行时间
  let execDate = +new Date()
  // 为每个setTimeOut添加标记,用于取消请求
  let throttlingId = null
  return function () {
    // 如果是第一次直接执行，并记录执行开始时间
    if (isFirst) {
      callback()
      execDate = +new Date()
      isFirst = false
    } else {
      const currDate = +new Date()
      // 下次执行如果超过time时间，可以执行
      if (currDate - execDate >= time) {
        callback()
        execDate = +new Date()
      } else {
        // 如果setTimeoutId 为真说明有请求在等待中，先把请求取消，把新的请求加入setTimeout
        if (throttlingId) {
          clearTimeout(throttlingId)
        }

        const waitDate = currDate + time - execDate
        throttlingId = setTimeout(() => {
          callback()
          execDate = +new Date()
        }, waitDate)
      }
    }
  }
}

/**
 * 条件函数通过，通过执行回调
 * @param {function} passFun  条件函数，通过执行回调
 * @param {function} callback 回调函数
 * @param {number}   time     条件函数不通过，间隔多久再去调用一次
 */
const timer = {}
export function dataExistCallFun(passFun, callback, time = 100, timeKey = getRandomStr()) {
  // 判断下拉项是否已经有，没有的话延时执行
  if (timer[timeKey]) clearTimeout(timer)
  delete timer[timeKey]
  if (passFun && passFun()) {
    if (callback) callback()
  } else {
    timer[timeKey] = setTimeout(() => {
      dataExistCallFun(passFun, callback, time, timeKey)
    }, time)
  }
}
